#lang scribble/doc
@(require scribble/manual "guide-utils.rkt"
          (for-label racket/flonum racket/place))

@;{@title[#:tag "effective-places"]{Parallelism with Places}}
@title[#:tag "effective-places"]{现场并行}

@;{The @racketmodname[racket/place] library provides support for
performance improvement through parallelism with the @racket[place]
form. The @racket[place] form creates a @deftech{place}, which is
effectively a new Racket instance that can run in parallel to other
places, including the initial place.  The full power of the Racket
language is available at each place, but places can communicate only
through message passing---using the @racket[place-channel-put] and
@racket[place-channel-get] functions on a limited set of
values---which helps ensure the safety and independence of parallel
computations.}
@racketmodname[racket/place]库通过与@racket[place]表的并行性来支持性能改进。@racket[place]表创建了一个@deftech{现场（place）}，这实际上是一个新的Racket实例，可以与其它地方（包括初始现场）并行运行。Racket语言的全部功能在每一个现场都可以使用，但现场只能通过消息传递进行通信——在有限的一组值上使用@racket[place-channel-put]和@racket[place-channel-get]函数——这有助于确保并行计算的安全性和独立性。

@;{As a starting example, the racket program below uses a @tech{place} to
determine whether any number in the list has a double that is also in
the list:}
作为一个开始的例子，下面的racket程序使用@tech{现场}来确定列表中的任何数是否具有在列表中的双位数：

@codeblock{
#lang racket

(provide main)

(define (any-double? l)
  (for/or ([i (in-list l)])
    (for/or ([i2 (in-list l)])
      (= i2 (* 2 i)))))

(define (main)
  (define p 
    (place ch
      (define l (place-channel-get ch))
      (define l-double? (any-double? l))
      (place-channel-put ch l-double?)))

  (place-channel-put p (list 1 2 4 8))
  
  (place-channel-get p))
}

@;{The identifier @racket[ch] after @racket[place] is bound to a @deftech{place
channel}. The remaining body expressions within the @racket[place] form
are evaluated in a new place, and the body expressions use @racket[ch]
to communicate with the place that spawned the new place.}
@racket[place]后面的标识@racket[ch]绑定到 @deftech{现场通道（place
channel）}。@racket[place]表中剩余的主体表达式将在一个新的现场求值，主体表达式使用@racket[ch]与生成新位置的现场进行通信。

@;{In the body of the @racket[place] form above, the new place receives a
list of numbers over @racket[ch] and binds the list to @racket[l].  It
then calls @racket[any-double?] on the list and binds the result to
@racket[l-double?]. The final body expression sends the
@racket[l-double?] result back to the original place over @racket[ch].}
在上面的@racket[place]表的主体中，新位置通过@racket[ch]接收一个数字列表，并将列表绑定到@racket[l]。它接着调用表上的@racket[any-double?]并将结果绑定到@racket[l-double?]。最终的主体表达式发送@racket[l-double?]结果返回@racket[ch]上的原始现场。

@;{In DrRacket, after saving and running the above program, evaluate
@racket[(main)] in the interactions window to create the new
place. @margin-note*{When using @tech{places} inside DrRacket, the
module containg place code must be saved to a file before it will
execute.}  Alternatively, save the program as @filepath{double.rkt}
and run from a command line with}
在DrRacket中，保存并运行上述程序后，在交互窗口对@racket[(main)]求值以创建新的现场。@margin-note*{在DrRacket中使用@tech{现场}时，必须将包含现场代码的模块保存到一个文件中，然后才能执行。}或者，将程序保存为@filepath{double.rkt}，并从一个命令行运行以下内容

@commandline{racket -tm double.rkt}

@;{where the @Flag{t} flag tells @exec{racket} to load the
@tt{double.rkt} module, the @Flag{m} flag calls the exported
@racket[main] function, and @Flag{tm} combines the two flags.}
其中，@Flag{t}标志告诉@exec{racket}加载@tt{double.rkt}模块，@Flag{m}标志调用导出的@racket[main]函数，同时@Flag{tm}将这两个标志组合起来。

@;{The @racket[place] form has two subtle features. First, it lifts the
@racket[place] body to an anonymous, module-level function.  This
lifting means that any binding referenced by the @racket[place] body
must be available in the module's top level. Second, the
@racket[place] form @racket[dynamic-require]s the enclosing module in
a newly created place. As part of the @racket[dynamic-require], the
current module body is evaluated in the new place.  The consequence of
this second feature is that @racket[place] should not appear immediately
in a module or in a function that is called in a module's top level;
otherwise, invoking the module will invoke the same module in a new
place, and so on, triggering a cascade of place creations that will
soon exhaust memory.}
@racket[place]表有两个微妙的特点。首先，它将@racket[place]主体提升到一个匿名的模块级函数。这种提升意味着，@racket[place]主体引用的任何绑定必须在模块的顶层可用。其次，@racket[place]表@racket[dynamic-require]在新创建的现场中包含封闭模块。作为@racket[dynamic-require]的一部分，当前模块主体将在新现场被求值。第二个特性的结果是，@racket[place]不应立即出现在模块中或在模块顶层调用的函数中；否则，调用模块将在新现场调用同一模块，以此类推，从而触发一系列位置创建，很快就会耗尽内存。

@codeblock{
#lang racket

(provide main)

; Don't do this!
(define p (place ch (place-channel-get ch)))

(define (indirect-place-invocation)
  (define p2 (place ch (place-channel-get ch))))

; Don't do this, either!
(indirect-place-invocation)
}

